package cn.ren.cloud.service.impl;

import cn.ren.cloud.doc.EsCourseDoc;
import cn.ren.cloud.domain.*;
import cn.ren.cloud.dto.CourseDto;
import cn.ren.cloud.enums.GlobelExceptionEnum;
import cn.ren.cloud.feign.EsCourseFeignClient;
import cn.ren.cloud.feign.MediaFeignClient;
import cn.ren.cloud.mapper.CourseMapper;
import cn.ren.cloud.result.JsonResult;
import cn.ren.cloud.service.*;
import cn.ren.cloud.utils.AssertUtil;
import cn.ren.cloud.vo.CourseDetailVo;
import cn.ren.cloud.vo.CourseInfoVo;
import cn.ren.cloud.vo.CourseOrderVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Ren
 * @since 2022-12-31
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    private final ICourseMarketService courseMarketService;
    private final ICourseResourceService courseResourceService;
    private final CourseMapper courseMapper;
    private final ICourseDetailService courseDetailService;
    private final ITeacherService teacherService;
    private final ICourseSummaryService courseSummaryService;
    private final ICourseTypeService courseTypeService;
    private final EsCourseFeignClient esCourseFeignClient;
    private final RocketMQTemplate rocketMQTemplate;
    private final ICourseChapterService courseChapterService;
    private final MediaFeignClient mediaFeignClient;

    public CourseServiceImpl(ICourseMarketService courseMarketService, ICourseResourceService courseResourceService, CourseMapper courseMapper, ICourseDetailService courseDetailService, ITeacherService teacherService, ICourseSummaryService courseSummaryService, ICourseTypeService courseTypeService, EsCourseFeignClient esCourseFeignClient, RocketMQTemplate rocketMQTemplate, ICourseChapterService courseChapterService, MediaFeignClient mediaFeignClient) {
        this.courseMarketService = courseMarketService;
        this.courseResourceService = courseResourceService;
        this.courseMapper = courseMapper;
        this.courseDetailService = courseDetailService;
        this.teacherService = teacherService;
        this.courseSummaryService = courseSummaryService;
        this.courseTypeService = courseTypeService;
        this.esCourseFeignClient = esCourseFeignClient;
        this.rocketMQTemplate = rocketMQTemplate;
        this.courseChapterService = courseChapterService;
        this.mediaFeignClient = mediaFeignClient;
    }

    @Override
    public void saveCourseAll(CourseDto courseDto) {
        Course course = courseDto.getCourse();
        CourseDetail courseDetail = courseDto.getCourseDetail();
        CourseMarket courseMarket = courseDto.getCourseMarket();
        CourseResource courseResource = courseDto.getCourseResource();
        List<Long> teacharIds = courseDto.getTeacharIds();
        // 1.参数校验使用JSR303
        // 2.业务校验
        // 2.1.查询课程是否已经存在，如果存在不允许新增
        selectCourseByName(course.getName());
        // 3.保存课程
        saveCourse(course, teacharIds);
        Long courseId = course.getId();
        // 4.保存课程详情
        saveCourseDetail(courseId, courseDetail);
        // 5.保存课程销售表
        saveCourseMarket(courseId, courseMarket);
        // 6.保存课程资源
        saveCourseResource(courseId, courseResource);
        // 7.初始化
        saveCourseSummary(courseId);
        // 8.保存课程与老师中间表信息
        courseMapper.saveCourseTeacher(courseId, teacharIds);
    }


    /**
     * 课程上架
     *
     * @param courseId
     */
    @Override
    public void onLineCourse(Long courseId) {
        // 参数效验
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, GlobelExceptionEnum.COURSE_IS_NULL);
        /*查询数据*/
        // 通过ID查找课程类型
        EsCourseDoc esCourseDoc = new EsCourseDoc();
        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());
        // 通过ID查找CourseMarket
        CourseMarket courseMarket = courseMarketService.selectById(course.getId());
        String chargeName = 1 == courseMarket.getCharge() ? "免费" : "收费";
        esCourseDoc.setChargeName(chargeName);
        // 通过ID查找CourseSummary
        CourseSummary courseSummary = courseSummaryService.selectById(course.getId());

        // 保存数据到数据库
        // 克隆
        BeanUtils.copyProperties(course, esCourseDoc);
        BeanUtils.copyProperties(courseMarket, esCourseDoc);
        BeanUtils.copyProperties(courseSummary, esCourseDoc);
        // 设置课程分类名称
        esCourseDoc.setCourseTypeName(courseType.getName());
        // 存入ES
        JsonResult esSave = esCourseFeignClient.saveCourseEs(esCourseDoc);
        AssertUtil.isTrue(esSave.isSuccess(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        // 修改课程状态和添加修改时间
        course.setStatus(Course.ONLINE);
        course.setOnlineTime(new Date());
        updateById(course);
        // 发送推送消息
        Message<Course> message = MessageBuilder.withPayload(course).build();
        rocketMQTemplate.sendOneWay("course-topic:course-tag", message);
    }

    /**
     * 获取课程详情
     *
     * @param id 课程ID
     */
    @Override
    public CourseDetailVo detailDate(Long id) {
        // 通过ID获取数据
        Course course = selectById(id);
        // 业务效验,判断是否为空，状态是否上架
        AssertUtil.isNotNull(course, GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        AssertUtil.isEquals(Course.ONLINE.toString(), course.getStatus().toString(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        CourseSummary courseSummary = courseSummaryService.selectById(id);
        CourseMarket courseMarket = courseMarketService.selectById(id);
        CourseDetail courseDetail = courseDetailService.selectById(id);
        List<Teacher> teachers = courseMapper.selectTeachersByCourseId(id);
        List<CourseChapter> courseChapters = selectCourseChaptersByCourseId(id);
        CourseDetailVo courseDetailVo = new CourseDetailVo();
        courseDetailVo.setCourse(course);
        courseDetailVo.setCourseDetail(courseDetail);
        courseDetailVo.setCourseMarket(courseMarket);
        courseDetailVo.setCourseSummary(courseSummary);
        courseDetailVo.setTeachers(teachers);
        courseDetailVo.setCourseChapters(courseChapters);
        return courseDetailVo;
    }

    /**
     * 通过IDs获取详情
     *
     * @param courseIds 课程IDS
     * @return 课程详情
     */
    @Override
    public CourseOrderVo getInfo(String courseIds) {
        // 获取IDS，进行分割
        String[] ids = courseIds.split(",");
        // 判断ids数组长度大于零
        AssertUtil.isTrue(ids.length > 0, GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        // 过滤空ID，转换成set排重
        Set<Long> collect = Arrays.stream(ids).filter(id -> !StringUtils.isEmpty(id)).map(Long::valueOf).collect(Collectors.toSet());
        // 判断过滤的数组长度和分割的长度是否一样
        AssertUtil.isTrue(ids.length == collect.size(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        // 查询所有IDS的课程信息
        List<Course> courses = selectBatchIds(collect);
        // 判断课程是否存在
        AssertUtil.isTrue(courses.size() > 0, GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        Map<Long, CourseMarket> marketMap = courseMarketService.selectBatchIds(collect).stream().collect(Collectors.toMap(CourseMarket::getId, courseMarket -> courseMarket));
        List<CourseInfoVo> courseInfoVos = new ArrayList<>();
        CourseOrderVo courseOrderVo = new CourseOrderVo();
        BigDecimal bigDecimal = new BigDecimal("0.0");
        for (Course course : courses){
            CourseInfoVo courseInfoVo = new CourseInfoVo();
            courseInfoVo.setCourse(course);
            CourseMarket courseMarket = marketMap.get(course.getId());
            courseInfoVo.setCourseMarket(courseMarket);
            courseInfoVos.add(courseInfoVo);
            bigDecimal = bigDecimal.add(courseMarket.getPrice());
        }
        courseOrderVo.setCourseInfos(courseInfoVos);
        courseOrderVo.setTotalAmount(bigDecimal);
        return courseOrderVo;
    }

    private List<CourseChapter> selectCourseChaptersByCourseId(Long id) {
        List<CourseChapter> courseChapters = courseChapterService.listByCourseId(id);
        JsonResult jsonResult = mediaFeignClient.getMediaFileByCourseId(id);
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        AssertUtil.isNotNull(jsonResult.getData(), GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
        List<MediaFile> mediaFiles = JSON.parseArray(JSON.toJSONString(jsonResult.getData()), MediaFile.class);
        // 3.为了减少双重for循环，将课程章节集合转换为map
        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));
        // 4.根据每个mediaFile的chapterId找到自己的chapter对象，放入到chapter对象的mediaFile集合中
        mediaFiles.forEach(e -> {
                    e.setFileUrl("");
                    courseChapterMap.get(e.getChapterId()).getMediaFiles().add(e);
                }
        );
        // 5.返回组装好的章节集合数据
        return courseChapters;
    }


    /**
     * 设置用户id
     *
     * @param courseId
     */
    private void saveCourseSummary(Long courseId) {
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(courseId);
        courseSummaryService.insert(courseSummary);
    }


    /**
     * 保存课程资源表
     *
     * @param courseId
     * @param courseResource
     */
    private void saveCourseResource(Long courseId, CourseResource courseResource) {
        courseResource.setCourseId(courseId);
        courseResourceService.insert(courseResource);
    }

    /**
     * 保存课程销售表
     *
     * @param courseId
     * @param courseMarket
     */
    private void saveCourseMarket(Long courseId, CourseMarket courseMarket) {
        courseMarket.setId(courseId);
        courseMarketService.insert(courseMarket);
    }

    /**
     * 保存课程详情
     *
     * @param courseId
     * @param courseDetail
     */
    private void saveCourseDetail(Long courseId, CourseDetail courseDetail) {
        courseDetail.setId(courseId);
        courseDetailService.insert(courseDetail);
    }

    private void saveCourse(Course course, List<Long> teacharIds) {
        course.setStatus(Course.OFFLINE);
        course.setLoginId(1L);
        course.setLoginUserName("yhptest");
        String teacherNames = teacherService.selectBatchIds(teacharIds).stream().map(Teacher::getName).collect(Collectors.joining(","));
        course.setTeacherNames(teacherNames);
        insert(course);
    }

    /**
     * 根据课程名称查询课程
     *
     * @param name
     */
    private void selectCourseByName(String name) {
        Wrapper<Course> wrapper = new EntityWrapper<>();
        wrapper.eq("name", name);
        Course course = selectOne(wrapper);
        AssertUtil.isNull(course, GlobelExceptionEnum.GLOBE_EXCEPTION_ENUM_PARAM_ERROR);
    }

}
